// Copyright (C) Kumo inc. and its affiliates.
// Author: Jeff.li lijippy@163.com
// All rights reserved.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published
// by the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program.  If not, see <https://www.gnu.org/licenses/>.
//

// Cast types to boolean

#include <nebula/array/builder_primitive.h>
#include <nebula/compute/kernels/common_internal.h>
#include <nebula/compute/kernels/scalar_cast_internal.h>
#include <nebula/util/value_parsing.h>

namespace nebula {

using internal::ParseValue;

namespace compute {
namespace internal {

struct IsNonZero {
  template <typename OutValue, typename Arg0Value>
  static OutValue Call(KernelContext*, Arg0Value val, turbo::Status*) {
    return val != 0;
  }
};

struct ParseBooleanString {
  template <typename OutValue, typename Arg0Value>
  static OutValue Call(KernelContext*, Arg0Value val, turbo::Status* st) {
    bool result = false;
    if (TURBO_UNLIKELY(!ParseValue<BooleanType>(val.data(), val.size(), &result))) {
      *st = turbo::invalid_argument_error("Failed to parse value: ", val);
    }
    return result;
  }
};

std::vector<std::shared_ptr<CastFunction>> GetBooleanCasts() {
  auto func = std::make_shared<CastFunction>("cast_boolean", Type::BOOL);
  AddCommonCasts(Type::BOOL, boolean(), func.get());
  AddZeroCopyCast(Type::BOOL, boolean(), boolean(), func.get());

  for (const auto& ty : numeric_types()) {
    ArrayKernelExec exec =
        generate_numeric<applicator::ScalarUnary, BooleanType, ArrayKernelExec, IsNonZero>(
            *ty);
    KCHECK_OK(func->add_kernel(ty->id(), {ty}, boolean(), exec));
  }
  for (const auto& ty : base_binary_types()) {
    ArrayKernelExec exec = generate_var_binary_base<applicator::ScalarUnaryNotNull,
                                                 BooleanType, ParseBooleanString>(*ty);
    KCHECK_OK(func->add_kernel(ty->id(), {ty}, boolean(), exec));
  }
  return {func};
}

}  // namespace internal
}  // namespace compute
}  // namespace nebula
